iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
Modern Web

30天一起搞懂Web觀念系列 第 4

[DAY4] JavaScript原型導向是什麼?

  • 分享至 

  • xImage
  •  

上回我們提到JavaScript的特性,所以就也整理了一篇原型導向

原型導向是什麼?

簡單來說就是沒有class,但仍然有物件導向的特性

(ES6 的 class 不是真的class,它只是語法糖)

這是什麼意思呢?


原型導向(Prototype-based)

每個物件生成的時候都會有一個原型(Prototype),透過原型鍵(Prototype chain)的方式可以將物件串起來,就達成物件導向的繼承了


我們看一個例子:

我們如果要生成一個實例的話會這樣寫

function Person(name) {  //創建一個person的構造函數
  this.name = name;
  this.sayHi = function () {
    console.log('Hi, I am ' + this.name);
  }
}

const p1 = new Person('Joanne'); //new 一個Joanne實例
const p2 = new Person('Ricky'); //new 一個Ricky實例

我們在console就可以看到

https://ithelp.ithome.com.tw/upload/images/20250807/20177952uUhRsTPZ0k.png

Joanne裡有namesayHi()、Ricky裡面也有namesayHi(),他們兩個人裡面的sayHi()明明再做同一件事,但卻被當成不一樣的函式裝在不同人裡面。

更好懂一點的講法,我們可以拿類別導向來一起說明,可以想像class是組餅乾模具,其中一個sayHi就是一種餅乾模具🍪

(餅乾模具就是這個👇)

https://ithelp.ithome.com.tw/upload/images/20250807/20177952UFWp8lWZdx.png

只要被它壓的(被他創建的)就會就具備這個能力(進到sayHi就會變成sayHi的樣子),而上面那個例子不是,他是把餅乾模具也複製一組起來,這樣就等於佔了新的一組的空間。
(我也不知道這樣會不會比較好懂一點)

所以為了解決,可以使用Prototype來讓他們共用一個函式

function Person(name) {
  this.name = name;
}

// 用Prototype加入sayHi()函式
Person.prototype.sayHi = function () {
  console.log('Hi, I am ' + this.name);
};

const p1 = new Person('Joanne');
const p2 = new Person('Ricky');

在console可以看到

https://ithelp.ithome.com.tw/upload/images/20250807/20177952TB5jZ4JZHE.png

我們發現sayHi()函式跑到[[Prototype]] 了!所有的Person實例就可以共享sayHi()

[[Prototype]] 其實就是原型鏈結,也記作__proto__

所以若更動sayHi(),每個Person都使用sayHi()時都會更動,因為 sayHi() 是存在於 Person.prototype 上,所有實例共用它。如果你改變 Person.prototype.sayHi 的內容,所有實例的行為都會跟著改變


另外,還有一個特性,它可以連結起來,什麼意思呢?

這延伸了上面的程式碼,我們多創建一個新的結構函式Dog,我希望他也可以有Person的方法,讓他成為一隻像人的狗 🐕

所以希望保有Dog自己的方法,也能有Person的方法

function Dog(name) {
  this.name = name;
}

// 這一行建立原型鏈:Dog → Person
Dog.prototype = Object.create(Person.prototype);

// 修正 constructor 指向
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function () {
  console.log('Woof!');
};

const d = new Dog('Buddy');

d.sayHi(); // 繼承自 Person 的方法
d.bark();  // 自己定義的方法

Dog.prototype = Object.create(Person.prototype);

這樣做會建立一個以 Person.prototype 為原型的新物件,並指定給 Dog.prototype,讓 Dog 繼承 Person 的方法。

但這樣會覆蓋掉原本的 constructor,因此我們通常會再補上一行:

Dog.prototype.constructor = Dog;

console可以看到

https://ithelp.ithome.com.tw/upload/images/20250807/20177952Wq6mjXQUfj.png

在程式碼中手動把Dog與Person之間串了一個原型鏈結(__proto__ ),我們不用想的太複雜,其實他就是一層一層往上的

  1. JavaScript 先去 dog.__proto__ 裡面找 sayHi
  2. 找不到,就往上找:dog.__proto__.__proto__,也就是 Person.prototype
  3. 找到 sayHi(),執行它

他們的關係大概像這樣👇,箭頭就是__proto__([[Prototype]])

https://ithelp.ithome.com.tw/upload/images/20250807/20177952t2OfxrvcUy.png


參考資料

https://zh.wikipedia.org/zh-tw/基于原型编程

https://blog.techbridge.cc/2017/04/22/javascript-prototype/

https://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html


上一篇
[DAY3] JavaScript是什麼?JS 引擎又是什麼?
下一篇
[DAY5] DOM 是什麼?
系列文
30天一起搞懂Web觀念30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言